package com.itxuhang.mvc.mapping;

import com.itxuhang.mvc.annotation.Controller;
import com.itxuhang.mvc.annotation.RequestMapping;
import com.itxuhang.mvc.handler.HandlerMethod;
import com.itxuhang.spring.aware.BeanFactoryAware;
import com.itxuhang.spring.factory.BeanFactory;
import com.itxuhang.spring.factory.DefaultListableBeanFactory;
import com.itxuhang.spring.init.InitializingBean;
import com.itxuhang.spring.po.BeanDefinition;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RequestMappingHandlerMapping implements HandlerMapping, BeanFactoryAware, InitializingBean {

    private Map<String, HandlerMethod> urlHandlers = new HashMap<>();
    private DefaultListableBeanFactory beanFactory;

    //根据请求URI查找对应的handler
    @Override
    public Object getHandler(HttpServletRequest request){
        String uri = request.getRequestURI();
        if(uri == null || uri.equals("")){
            return null ;
        }
        return this.urlHandlers.get(uri);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    @Override
    public void afterPropertiesSet() {
        List<BeanDefinition> beanDefinitions = beanFactory.getBeanDefinitions();
        for (BeanDefinition bd : beanDefinitions) {
            Class clazzType = bd.getClazzType();
            String beanName = bd.getBeanName();
            // 判断是否是基于注解的处理器类
            if (isHandler(clazzType)){
                Method[] methods = clazzType.getDeclaredMethods();
                // 得到RequestMapping对象，最终获取其中的value值
                RequestMapping classRequestMapping = (RequestMapping) clazzType.getAnnotation(RequestMapping.class);
                String classUrl = classRequestMapping.value();
                for (Method method : methods) {
                    if(method.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
                        String methodUrl = methodRequestMapping.value();
                        String url = combine(classUrl,methodUrl);

                        HandlerMethod hm = new HandlerMethod(beanFactory.getBean(beanName),method);
                        urlHandlers.put(url,hm);
                    }
                }
            }
        }
    }

    private String combine(String classUrl, String methodUrl) {
        StringBuffer sb = new StringBuffer();
        if (classUrl != null && !classUrl.equals("")){
            classUrl = classUrl.startsWith("/") ? classUrl: "/" + classUrl;
            sb.append(classUrl);
        }
        if (methodUrl != null && !methodUrl.equals("")){
            methodUrl = methodUrl.startsWith("/") ? methodUrl: "/" + methodUrl;
            sb.append(methodUrl);
        }
        return sb.toString();
    }

    private boolean isHandler(Class clazzType) {
        return clazzType.isAnnotationPresent(Controller.class) || clazzType.isAnnotationPresent(RequestMapping.class);
    }
}
